package com.engine.modules.ytht.service;

import com.engine.common.baseEntity.gis.BoxRangeEntity;
import com.engine.common.exception.MapperException;
import com.engine.common.exception.ServiceException;
import com.engine.common.exception.SystemTableException;
import com.engine.common.util.CacheUtil.MyCacheUtil;
import com.engine.common.util.GeoUtil.GeomCaculateUtil;
import com.engine.common.util.ListMapAndJson;
import com.engine.init.Globle;
import com.engine.init.entity.GroupPropertiesEntity;
import com.engine.init.entity.TablePropertieEntity;
import com.engine.init.entity.TableToGroupEntity;
import com.engine.modules.general.mapper.GeneralDataCommonMapper;
import com.engine.modules.vector.mapper.VectorSourceMapper;
import com.engine.modules.vector.mapper.VectorTilesMapper;
import com.engine.modules.ytht.entity.FieldBlockUpdateResultEntity;
import com.engine.modules.ytht.entity.PlotInfoEntity;
import com.engine.modules.ytht.mapper.FieldBlockBindingMapper;
import com.engine.modules.ytht.util.BusinessCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

@Slf4j
@Service
public class FieldBlockBindingServiceImpl implements FieldBlockBindingService {

    @Autowired
    GeneralDataCommonMapper generalDataCommonMapper;

    @Autowired
    VectorTilesMapper vectorTilesMapper;

    @Autowired
    VectorSourceMapper vectorSourceMapper;

    @Autowired
    FieldBlockBindingMapper fieldBlockBindingMapper;

    @Autowired
    CacheManager cacheManager;


    @Override
    @Cacheable(value = "vectorTilesCache",key = "'FieldBlock:put:'+#z+':'+#x+':'+#y")
    public byte[] selectPacUnionTileByXYZ(int z, int x, int y, String tablePac) {
        if(tablePac.length()>6)
            tablePac=tablePac.substring(0,5);
        if(z<15)
            return new byte[0];
        byte[] bytes = vectorTilesMapper.selectPacUnionTileByXYZ(z, x, y,tablePac,
                "FieldBlock","b_gis_polygon_qqcg_x", "b_gis_polygon_qqcg_x","", "b_gis_polygon_location_box_xian",
                "");
        return bytes;
    }

    @Override
    @Cacheable(value = "vectorTilesCache",key = "'FieldBlock:pout:'+#z+':'+#x+':'+#y")
    public byte[] selectOverwisePacUnionTileByXYZ(int z, int x, int y, String tablePac) {
        if(tablePac.length()>6)
            tablePac=tablePac.substring(0,5);
        String endHalfName="_lv";
        if(z>14)
            return new byte[0];
        else if(z<=14&&z>12)
            endHalfName+="14";
        else if(z<=12&&z>10)
            endHalfName+="12";
        else if(z<=10&&z>8)
            endHalfName+="10";
        else if(z<=8)
            endHalfName+="8";
        byte[] bytes = vectorTilesMapper.selectPacUnionTileByXYZ(z, x, y,tablePac,
                "FieldBlock","b_gis_polygon_qqcg_x", "b_gis_polygon_qqcg_x",endHalfName, "b_gis_polygon_location_box_xian",
                "");
        return bytes;
    }

    @Override
    @Cacheable(value = "geoJsonCache",key = "'FieldBlock:ggid:'+#fbId",unless="#result == null")
    public List<Map<String, Object>> selectGroupGeojsonByFBId(String fbId, String groupName) {
        String tableName = getTableNameByFieldBlockNo(fbId);
        String wherestr = "field_black_no='" + fbId + "'";
        List<Map<String, Object>> result = vectorSourceMapper.selectGeojsonByWhereStr(tableName, wherestr, "");
        if (result.size() == 1)
            return result;
        else if (result.size() == 0)
            return null;
        else
            throw new SystemTableException("表中fbId重复");
    }

    @Override
    @Cacheable(value = "geoJsonCache",key = "'FieldBlock:ggtfid:'+#tfIdc")
    public List<Map<String, Object>> selectGroupGeojsonByTfIdc(String tfIdc, String groupName, String tablePac) {
        List<Map<String, Object>> result = new ArrayList<>();
        String wherestr = "tf_idc='" + tfIdc + "'";
        List<String> tables = getTableName(tablePac, groupName);
        for (String tableName : tables) {
            result.addAll(vectorSourceMapper.selectGeojsonByWhereStr(tableName, wherestr, ""));
        }
        return result;
    }

    @Override
    @Cacheable(value = "geoJsonCache",key = "'FieldBlock:ggcbjyqztidcard'+#cbjyqztidcard")
    public List<Map<String, Object>> selectGroupGeojsonBycbjyqztidcard(String tfIdc, String groupName, String tablePac) {
        List<Map<String, Object>> result = new ArrayList<>();
        String wherestr = "cbjyqztidcard='" + tfIdc + "'";
        List<String> tables = getTableName(tablePac, groupName);
        for (String tableName : tables) {
            result.addAll(vectorSourceMapper.selectGeojsonByWhereStr(tableName, wherestr, ""));
        }
        return result;
    }

    @Override
    @Cacheable(value = "geoJsonCache",key = "'FieldBlock:gd:'+#fbId")
    public Map<String, Object> selectGroupDataByFBId(String fbId, String groupName) {
        String tableName = getTableNameByFieldBlockNo(fbId);
        String wherestr = "field_black_no='" + fbId + "'";
        List<Map<String, Object>> result = generalDataCommonMapper.selectDataByWhereStr(tableName,
                    wherestr, "");
        if (result.size() == 1)
            return result.get(0);
        else if(result.size() == 0)
            return null;
        else
            throw new SystemTableException("表中fbId重复");
    }
    @Override
    @Cacheable(value = "dataCache",key = "'FieldBlock:no2id:'+#fieldBlockNo")
    public String selectIdByFieldBlockNo(String fieldBlockNo) {
        return fieldBlockBindingMapper.selectIdByFieldblackNo(fieldBlockNo);
    }

    @Override
    public List<String> UpdateGroupGeneralDataByMutiEntity(List<PlotInfoEntity> lietEntity, String groupName)
            throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        List<String> result = new ArrayList();
        for (PlotInfoEntity plotInfo : lietEntity) {
            String s = UpdateGroupGeneralDataByEntity(plotInfo, groupName);
            if (!s.equals(""))
                result.add(s);
        }
        return result;
    }

    @Override
    public String UpdateGroupGeneralDataByEntity(PlotInfoEntity lietEntity, String groupName)
            throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        String fbId=lietEntity.getField_black_no();
        try{
            String tableName = getTableNameByFieldBlockNo(fbId);
            fbId = generalDataCommonMapper.updateByEntity(lietEntity, "field_black_no", tableName);
            if (!fbId.equals("")) {
                rmVectorCacheByFbId(cacheManager, tableName, fbId);
                return fbId;
            }
            return "";
        }catch (Exception e)
        {
            return "";
        }
    }

    @Override
    public FieldBlockUpdateResultEntity insertByGeojson(String tablePac, String geoJson, String groupName) {
//        log.info(String.valueOf(1));
        long startTime=(new Date()).getTime();
        List<String> tableNames = getTableName(tablePac, groupName);
        FieldBlockUpdateResultEntity fb = new FieldBlockUpdateResultEntity();
        if (tableNames.size() != 1||tablePac.length()>6)
        {
            fb.setStatus(0);
            fb.setMsg("tablePac不合规");
            return fb;
        }
        String tableName = tableNames.get(0);
        List<Map<String, Object>> listMap;
        try{
            listMap = ListMapAndJson.Geojson2ListMap(geoJson);
            if (listMap.size() == 0)
            {
                fb.setStatus(0);
                fb.setMsg("geojson格式有误");
                return fb;
            }
        }
        catch (Exception e)
        {
            fb.setStatus(0);
            fb.setMsg("geojson格式有误");
            return fb;
        }
        Map<String, Object> map = listMap.get(0);
        String geojson= map.get("geom").toString();
        String checkVectorRs=fieldBlockBindingMapper.checkVectorError(geojson);
        fb.setVaildCheckResult(checkVectorRs);
        if (!checkVectorRs.equals("Valid Geometry"))
        {
            fb.setStatus(0);
            fb.setMsg("geometry有矢量错误："+checkVectorRs);
            return fb;
        }
        List<String> intersectsList=fieldBlockBindingMapper.getIntersectsBlockFbId(geojson,tableName);
        if(map.get("field_cross_nos")!=null)
            map.remove("field_cross_nos");
        if (intersectsList.size()!=0)
        {
            fb.setStatus(2);
            fb.setMsg("警告，存在和原有地块碰撞问题");
            fb.setIntersectsList(intersectsList);
            String ss="";
            for (String iid:intersectsList) {
                ss=ss+iid+",";
            }
            ss=ss.substring(0,ss.length()-1);
            if(ss.length()>255)
                ss=ss.substring(0,255);
            map.put("field_cross_nos",ss);
        }
        else
            fb.setStatus(1);
        String rs = fieldBlockBindingMapper.fieldBlockBindingInsertByMapGeoJson(tablePac, map, tableName);

        if (!rs.equals("")) {
            fb.setId(rs);
            rmVectorCacheByFbId(cacheManager, tableName, rs);
            long endTime=(new Date()).getTime();
            fb.setDuration(endTime-startTime);
            return fb;
        }
        else
        {
            fb.setStatus(0);
            fb.setMsg("插入数据失败");
            return fb;
        }
    }

    @Override
    public FieldBlockUpdateResultEntity updateByGeojson(String geoJson, String groupName) {
        FieldBlockUpdateResultEntity fb = new FieldBlockUpdateResultEntity();
        List<Map<String, Object>> listMap;
        try{
            listMap = ListMapAndJson.Geojson2ListMap(geoJson);
            if (listMap.size() == 0)
            {
                fb.setStatus(0);
                fb.setMsg("geojson格式有误");
                return fb;
            }
        }
        catch (Exception e)
        {
            fb.setStatus(0);
            fb.setMsg("geojson格式有误");
            return fb;
        }
        Map<String, Object> map = listMap.get(0);
        String fbId=map.get("field_black_no").toString();
        if(fbId==null)
            throw new ServiceException("geojson中未包含field_black_no");
        String tableName = getTableNameByFieldBlockNo(fbId);
        String tablePac=fbId.substring(0,6);
        String geojson= map.get("geom").toString();
        String checkVectorRs=fieldBlockBindingMapper.checkVectorError(geojson);
        fb.setVaildCheckResult(checkVectorRs);
        if (!checkVectorRs.equals("Valid Geometry"))
        {
            fb.setStatus(0);
            fb.setMsg("geometry有矢量错误："+checkVectorRs);
            return fb;
        }
        List<String> intersectsList=fieldBlockBindingMapper.getIntersectsBlockFbId(geojson,tableName);
        if(map.get("field_cross_nos")!=null)
            map.remove("field_cross_nos");
        for (int i=0;i<intersectsList.size();i++) {
            if(intersectsList.get(i).equals(fbId))
                intersectsList.remove(i);
        }
        if (intersectsList.size()!=0)
        {
            fb.setStatus(2);
            fb.setMsg("警告，存在和原有地块碰撞问题");
            fb.setIntersectsList(intersectsList);
            String ss="";
            for (String iid:intersectsList) {
                ss=ss+iid+",";
            }
            ss=ss.substring(0,ss.length()-1);
            if(ss.length()>255)
                ss=ss.substring(0,255);
            map.put("field_cross_nos",ss);
        }
        else
            fb.setStatus(1);
        String rs=fieldBlockBindingMapper.fieldBlockBindingUpdateByMapGeoJson(tablePac,map,tableName,"");
        if (!rs.equals("")) {
            fb.setId(rs);
            rmVectorCacheByFbId(cacheManager, tableName, rs);
            return fb;
        }
        else
        {
            fb.setStatus(0);
            fb.setMsg("更新数据失败");
            return fb;
        }
    }

    @Override
    public String deleteByFbIdLogic(String fbId, String groupName) {
        String tableName = getTableNameByFieldBlockNo(fbId);
        String rs = fieldBlockBindingMapper.deleteLogicByFbId(fbId, tableName, "");
        rmVectorCacheByFbId(cacheManager, tableName, rs);
        return rs;
    }

    @Override
    @Transactional
    public String deleteByFbId(String fbId, String groupName) {
        String rs=deleteByFbIdLogic(fbId,groupName);
        String tableName = getTableNameByFieldBlockNo(fbId);
        if(!rs.equals("")) {
            String r2 = fieldBlockBindingMapper.deleteByFbId(fbId, tableName, "");
            return r2;
        }
        return rs;
    }

    //清除矢量切片和geojson的缓存
    public void rmVectorCacheByFbId(CacheManager cacheManager,String tableName, String fbId) {
        String tfIdc=generalDataCommonMapper.selectTfIdcByFbId(tableName,fbId);
        TablePropertieEntity tablePropertieEntity=Globle.TablePropertiesMap.get(tableName);
        rmVectorTileCacheByFbId(cacheManager,tableName, "FieldBlock:put:", fbId, tablePropertieEntity.getMinz(), tablePropertieEntity.getMaxz());
        MyCacheUtil.rmBykey(cacheManager, "geoJsonCache", "FieldBlock:gd:" , fbId);
        MyCacheUtil.rmBykey(cacheManager, "geoJsonCache", "FieldBlock:ggid:" , fbId);
        MyCacheUtil.rmBykey(cacheManager, "geoJsonCache", "FieldBlock:ggtfid:" , tfIdc);
    }

    //根据table_pac和group获取tablename
    public List<String> getTableName(String tablePac,String groupName)
    {
        GroupPropertiesEntity propertiesEntity = Globle.GroupPropertiesMap.get(groupName);
        if (propertiesEntity == null)
            throw new SystemTableException("数据组表中没有此组");
        if(tablePac.length()>6)
            tablePac=tablePac.substring(0,5);
        List<String> rs=new ArrayList<>();
        String tableName=groupName+tablePac;
        if(tablePac.length()==6)
        {
            if (Globle.TablePropertiesMap.get(tableName) == null)
                throw new MapperException("tablePac输入有误");
            rs.add(tableName);
            return rs;
        }
        else
        {
            for (TableToGroupEntity tableToGroupEntity :propertiesEntity.getListTableToGroupEntity()) {
                if(tableToGroupEntity.getTableName().contains(tableName))
                {
                    if (Globle.TablePropertiesMap.get(tableToGroupEntity.getTableName()) == null)
                        throw new SystemTableException("表未输入管理表");
                    rs.add(tableToGroupEntity.getTableName());
                }
            }
            if(rs.size()==0)
                throw new MapperException("tablePac输入有误");
            return rs;
        }
    }


    public void rmVectorTileCacheByFbId(CacheManager cacheManager,String tableName, String keyFirstHalf, String fbId, int minz, int maxz) {
        BoxRangeEntity boxRangeEntity = generalDataCommonMapper.selectBoxRangeByWhereStr(tableName,
                "field_black_no='"+fbId+"'");
        if (boxRangeEntity == null)
            return;
        List<String> stringList = GeomCaculateUtil.LngLatRangeToTileNumListString(minz, maxz, boxRangeEntity);
        MyCacheUtil.rmBykeyList(cacheManager, "vectorTilesCache",keyFirstHalf, stringList);
    }

    public String getTableNameByFieldBlockNo(String fieldBlockNo ) {
        if (!Pattern.matches("53[0-9]{13}", fieldBlockNo))
            throw new MapperException("fieldblackNo不合规");
        String tablePac = fieldBlockNo.substring(0, 6);
        String groupName = "b_gis_polygon_qqcg_x";
        if (Globle.TablePropertiesMap.get(groupName + tablePac) == null)
            throw new MapperException("fieldblackNo中pac对应区域无数据");
        return groupName + tablePac;
    }


}
